package whf.framework.util.var;

import java.util.Iterator;
import java.util.Map;

import javax.servlet.http.HttpSession;

import whf.framework.log.Log;
import whf.framework.log.LogFactory;
import whf.framework.security.UserContext;
import whf.framework.util.StringUtils;
import whf.framework.util.Utils;
import whf.framework.web.WebContextHolder;

/**
 * @author wanghaifeng
 *
 */
public class VariableHolderFactory {
	private static Log log = LogFactory.getLog(VariableHolderFactory.class);
	
	private static HolderListener holderListener = new HolderListener();
	
	
	//适用于上下文环境相关的变量定义，如session， request等
	private static Map<String, Class<? extends VariableHolder>> definitions = Utils.newHashMap();
	
	// Holder always exists
	private static Map<String, VariableHolder> globalHolders = Utils.newHashMap();
	
	// Holder exists in 
	private static ThreadLocal<Map<String, VariableHolder>> threadsHolders = new ThreadLocal<Map<String, VariableHolder>>();
	
	// Holders exists in session
	private static Map<HttpSession, Map<String, VariableHolder>> sessionScopeHolders = Utils.newHashMap();

	static{
		definitions.put("session", SessionVariableHolder.class);
		definitions.put("request", RequestVariableHolder.class);
		definitions.put("request.attribute", RequestAttributeVariableHolder.class);
		definitions.put("request.parameter", RequestParameterVariableHolder.class);
		definitions.put("userContext", UserContextVariableHolder.class);
		
		globalHolders.put("datetime", new DatetimeVariableHolder());
		globalHolders.put("sequence", new SequenceVariableHolder());
		
		//
		//holderListener.start();
	}

	public static void registerDefinition(String key, Class<? extends VariableHolder> cls){
		if(StringUtils.isEmpty(key) || cls == null){
			throw new IllegalArgumentException("key or class is empty!");
		}
		definitions.put(key, cls);
	}
	
	public synchronized static void registerHolder(String key, VariableHolder holder) {
		if(StringUtils.isEmpty(key) || holder == null){
			throw new IllegalArgumentException("key or holder is empty!");
		}
		VariableHolderScope scope = holder.getScope();
		if(scope == VariableHolderScope.THREAD) {
			Map<String, VariableHolder> holders = threadsHolders.get();
			if(holder == null){
				holders = Utils.newHashMap();
				threadsHolders.set(holders);
			}
			holders.put(key, holder);
		} else if(scope == VariableHolderScope.SESSION) {
			HttpSession session = WebContextHolder.getWebContext().getSession();
			Map<String, VariableHolder> holders = sessionScopeHolders.get(session);
			if(holder == null){
				holders = Utils.newHashMap();
				sessionScopeHolders.put(session, holders);
			}
			holders.put(key, holder);
		} else {
			globalHolders.put(key, holder);
		}
		log.debug(key + "\n" + holder);
	}
	
	public static VariableHolder getVairiableHolder(String holderName) {
		VariableHolder result = null;
		if(globalHolders.containsKey(holderName)) {
			result = globalHolders.get(holderName);
		} else {
			Map<String, VariableHolder> holders = threadsHolders.get();
			if(holders.containsKey(holderName)) {
				result = holders.get(holderName);
			} else {
				HttpSession session = WebContextHolder.getWebContext().getSession();
				holders = sessionScopeHolders.get(session);
				if(holders.containsKey(holderName)) {
					result = holders.get(holderName);
				}
			}
		}
		if(result != null){
			return result;
		} else {
			Class cls = definitions.get(holderName);
			if(cls == null){
				throw new IllegalArgumentException("Holder name is not fefined!");
			} else {
				try{
					result = (VariableHolder)cls.newInstance();
					registerHolder(holderName, result);
					return result;
				} catch(Exception e){
					log.debug(e);
					throw new IllegalArgumentException(e);
				}
			}
		}
	}
	
	/**
	 * remove invalidate session holders
	 * @author wanghaifeng
	 *
	 */
	private static class HolderListener extends Thread {
		public void run(){
			while(true){
				synchronized(sessionScopeHolders){
					for(Iterator it = sessionScopeHolders.keySet().iterator(); it.hasNext(); ){
						HttpSession session = (HttpSession)it.next();
						try{
							session.getAttribute(UserContext.class.getName());
						} catch(Exception e){
							it.remove();
						}
					}
				}
				try{
					Thread.sleep(1000 * 60 * 5);
				} catch(Exception e){
					
				}
			}
		}
	}
}
